/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de>
  
  Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;

using System.Diagnostics;

using KeePassLib.Resources;
using KeePassLib.Serialization;
using Android.Webkit;

namespace KeePassLib.Utility
{
  public enum MessageBoxButtons
  {
    OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel
  }
  public enum MessageBoxIcon
  {
    Information, Warning, Error, Question
  }
  public enum MessageBoxDefaultButton
  {
    Button1, Button2, Button3
  }

  public enum DialogResult
  {
    Yes, No, Cancel, Retry, Abort
  }


  public sealed class MessageServiceEventArgs : EventArgs
  {
    private string m_strTitle = string.Empty;
    private string m_strText = string.Empty;
    //private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
    //private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;

    public string Title { get { return m_strTitle; } }
    public string Text { get { return m_strText; } }
    //public MessageBoxButtons Buttons { get { return m_msgButtons; } }
    //public MessageBoxIcon Icon { get { return m_msgIcon; } }

    public MessageServiceEventArgs() { }

    public MessageServiceEventArgs(string strTitle, string strText,
        MessageBoxButtons msgButtons, MessageBoxIcon msgIcon)
    {
      m_strTitle = (strTitle ?? string.Empty);
      m_strText = (strText ?? string.Empty);

    }
  }

  public static class MessageService
  {
    private static volatile uint m_uCurrentMessageCount = 0;

#if !KeePassLibSD
    private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Information;
    private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
    private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;

#else
		private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
		private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
		private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
#endif
    //private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;

    public static string NewLine
    {
#if !KeePassLibSD
      get { return Environment.NewLine; }
#else
			get { return "\r\n"; }
#endif
    }

    public static string NewParagraph
    {
#if !KeePassLibSD
      get { return Environment.NewLine + Environment.NewLine; }
#else
			get { return "\r\n\r\n"; }
#endif
    }

    public static uint CurrentMessageCount
    {
      get { return m_uCurrentMessageCount; }
    }

    public static event EventHandler<MessageServiceEventArgs> MessageShowing;

    private static string ObjectsToMessage(object[] vLines)
    {
      return ObjectsToMessage(vLines, false);
    }

    private static string ObjectsToMessage(object[] vLines, bool bFullExceptions)
    {
      if (vLines == null) return string.Empty;

      string strNewPara = MessageService.NewParagraph;

      StringBuilder sbText = new StringBuilder();
      bool bSeparator = false;

      foreach (object obj in vLines)
      {
        if (obj == null) continue;

        string strAppend = null;

        Exception exObj = (obj as Exception);
        string strObj = (obj as string);
#if (!KeePassLibSD && !KeePassRT)
        StringCollection scObj = (obj as StringCollection);
#endif

        if (exObj != null)
        {
          if (bFullExceptions)
            strAppend = StrUtil.FormatException(exObj);
          else if ((exObj.Message != null) && (exObj.Message.Length > 0))
            strAppend = exObj.Message;
        }
#if (!KeePassLibSD && !KeePassRT)
        else if (scObj != null)
        {
          StringBuilder sb = new StringBuilder();
          foreach (string strCollLine in scObj)
          {
            if (sb.Length > 0) sb.AppendLine();
            sb.Append(strCollLine.TrimEnd());
          }
          strAppend = sb.ToString();
        }
#endif
        else if (strObj != null)
          strAppend = strObj;
        else
          strAppend = obj.ToString();

        if (!string.IsNullOrEmpty(strAppend))
        {
          if (bSeparator) sbText.Append(strNewPara);
          else bSeparator = true;

          sbText.Append(strAppend);
        }
      }

      return sbText.ToString();
    }

#if (!KeePassLibSD && !KeePassRT)
    /*internal static Form GetTopForm()
    {
        FormCollection fc = Application.OpenForms;
        if((fc == null) || (fc.Count == 0)) return null;

        return fc[fc.Count - 1];
    }*/
#endif

    private static DialogResult SafeShowMessageBox(string strText, string strTitle,
        MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
    {
#if (KeePassLibSD || KeePassRT)
			return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else

      if (mb == MessageBoxButtons.OK)
      {
        //Android.Widget.Toast toast = ..
      }
      //this might help: http://www.gregshackles.com/2011/04/using-background-threads-in-mono-for-android-applications/
      throw new NotImplementedException();
      /*IWin32Window wnd = null;
      try
      {
          Form f = GetTopForm();
          if((f != null) && f.InvokeRequired)
              return (DialogResult)f.Invoke(new SafeShowMessageBoxInternalDelegate(
                  SafeShowMessageBoxInternal), f, strText, strTitle, mb, mi, mdb);
          else wnd = f;
      }
      catch(Exception) { Debug.Assert(false); }

      if(wnd == null)
      {
          if(StrUtil.RightToLeft)
              return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
          return MessageBox.Show(strText, strTitle, mb, mi, mdb);
      }

      try
      {
          if(StrUtil.RightToLeft)
              return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb, m_mboRtl);
          return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb);
      }
      catch(Exception) { Debug.Assert(false); }

      if(StrUtil.RightToLeft)
          return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
      return MessageBox.Show(strText, strTitle, mb, mi, mdb);
      */
#endif
    }

#if (!KeePassLibSD && !KeePassRT)
    /*	internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
        string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
        MessageBoxDefaultButton mdb);

    internal static DialogResult SafeShowMessageBoxInternal(IWin32Window iParent,
        string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
        MessageBoxDefaultButton mdb)
    {
        if(StrUtil.RightToLeft)
            return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
        return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
    }*/
#endif

    public static void ShowInfo(params object[] vLines)
    {
      ShowInfoEx(null, vLines);
    }

    public static void ShowInfoEx(string strTitle, params object[] vLines)
    {
      ++m_uCurrentMessageCount;

      strTitle = (strTitle ?? PwDefs.ShortProductName);
      string strText = ObjectsToMessage(vLines);

      if (MessageService.MessageShowing != null)
        MessageService.MessageShowing(null, new MessageServiceEventArgs(
            strTitle, strText, MessageBoxButtons.OK, m_mbiInfo));

      SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiInfo,
          MessageBoxDefaultButton.Button1);

      --m_uCurrentMessageCount;
    }

    public static void ShowWarning(params object[] vLines)
    {
      ShowWarningPriv(vLines, false);
    }

    internal static void ShowWarningExcp(params object[] vLines)
    {
      ShowWarningPriv(vLines, true);
    }

    private static void ShowWarningPriv(object[] vLines, bool bFullExceptions)
    {
      ++m_uCurrentMessageCount;

      string strTitle = PwDefs.ShortProductName;
      string strText = ObjectsToMessage(vLines, bFullExceptions);

      if (MessageService.MessageShowing != null)
        MessageService.MessageShowing(null, new MessageServiceEventArgs(
            strTitle, strText, MessageBoxButtons.OK, m_mbiWarning));

      SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiWarning,
          MessageBoxDefaultButton.Button1);

      --m_uCurrentMessageCount;
    }

    public static void ShowFatal(params object[] vLines)
    {
      ++m_uCurrentMessageCount;

      string strTitle = PwDefs.ShortProductName + @" - " + KLRes.FatalError;
      string strText = KLRes.FatalErrorText + MessageService.NewParagraph +
          KLRes.ErrorInClipboard + MessageService.NewParagraph +
          // Please send it to the KeePass developers.
          // KLRes.ErrorFeedbackRequest + MessageService.NewParagraph +
          ObjectsToMessage(vLines);

      try
      {
#if !KeePassLibSD
        /* nicht benoetigt - hoffentlich :-)
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true));*/
#else
				Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
#endif
      }
      catch (Exception) { Debug.Assert(false); }

      if (MessageService.MessageShowing != null)
        MessageService.MessageShowing(null, new MessageServiceEventArgs(
            strTitle, strText, MessageBoxButtons.OK, m_mbiFatal));

      SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiFatal,
          MessageBoxDefaultButton.Button1);

      --m_uCurrentMessageCount;
    }

    public static DialogResult Ask(string strText, string strTitle,
        MessageBoxButtons mbb)
    {
      ++m_uCurrentMessageCount;

      string strTextEx = (strText ?? string.Empty);
      string strTitleEx = (strTitle ?? PwDefs.ShortProductName);

      if (MessageService.MessageShowing != null)
        MessageService.MessageShowing(null, new MessageServiceEventArgs(
            strTitleEx, strTextEx, mbb, MessageBoxIcon.Question));

      DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
                                           MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

      --m_uCurrentMessageCount;
      return dr;
    }

    public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes,
        MessageBoxIcon mbi)
    {
      ++m_uCurrentMessageCount;

      string strTextEx = (strText ?? string.Empty);
      string strTitleEx = (strTitle ?? PwDefs.ShortProductName);

      if (MessageService.MessageShowing != null)
        MessageService.MessageShowing(null, new MessageServiceEventArgs(
            strTitleEx, strTextEx, MessageBoxButtons.YesNo, MessageBoxIcon.Question));

      DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
                                           MessageBoxButtons.YesNo, MessageBoxIcon.Question, bDefaultToYes ?
          MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);

      --m_uCurrentMessageCount;
      return (dr == DialogResult.Yes);
    }

    public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
    {
      return AskYesNo(strText, strTitle, bDefaultToYes, MessageBoxIcon.Question);
    }

    public static bool AskYesNo(string strText, string strTitle)
    {
      return AskYesNo(strText, strTitle, true, MessageBoxIcon.Question);
    }

    public static bool AskYesNo(string strText)
    {
      return AskYesNo(strText, null, true, MessageBoxIcon.Question);
    }

    public static void ShowLoadWarning(string strFilePath, Exception ex)
    {
      ShowLoadWarning(strFilePath, ex, false);
    }

    public static void ShowLoadWarning(string strFilePath, Exception ex,
        bool bFullException)
    {
      string str = string.Empty;

      if ((strFilePath != null) && (strFilePath.Length > 0))
        str += strFilePath + MessageService.NewParagraph;

      str += KLRes.FileLoadFailed;

      if ((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
      {
        str += MessageService.NewParagraph;
        if (!bFullException) str += ex.Message;
        else str += ObjectsToMessage(new object[] { ex }, true);
      }

      ShowWarning(str);
    }

    public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
    {
      if (ioConnection != null)
        ShowLoadWarning(UrlUtil.GetFileName(ioConnection.Path), ex, false);
      else ShowWarning(ex);
    }

    public static void ShowSaveWarning(string strFilePath, Exception ex,
        bool bCorruptionWarning)
    {
      FileLockException fl = (ex as FileLockException);
      if (fl != null)
      {
        ShowWarning(fl.Message);
        return;
      }

      string str = string.Empty;
      if ((strFilePath != null) && (strFilePath.Length > 0))
        str += strFilePath + MessageService.NewParagraph;

      str += KLRes.FileSaveFailed2;

      if ((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
        str += MessageService.NewParagraph + ex.Message;

      if (bCorruptionWarning)
        str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;

      ShowWarning(str);
    }

    public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex,
        bool bCorruptionWarning)
    {
      if (ioConnection != null)
        ShowSaveWarning(UrlUtil.GetFileName(ioConnection.Path), ex, bCorruptionWarning);
      else ShowWarning(ex);
    }

    public static void ExternalIncrementMessageCount()
    {
      ++m_uCurrentMessageCount;
    }

    public static void ExternalDecrementMessageCount()
    {
      --m_uCurrentMessageCount;
    }
  }
}
